/**
 * Copyright 2000 self.com.au
 *
 * Licensed under the Apache License, Version 2.0 (the "License");
 * you may not use this file except in compliance with the License. (http://www.apache.org/licenses/LICENSE-2.0)
 *
 * Unless required by applicable law or agreed to in writing, software distributed under the License is distributed 
 * on an "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the License for 
 * the specific language governing permissions and limitations under the License.
 *
 * <dhamma-message src="Atisha (11th century Tibetan Buddhist master)">
 * 	The greatest achievement is selflessness. The greatest worth is self-mastery.
 * 	The greatest quality is seeking to serve others. The greatest precept is continual awareness.
 * 	The greatest medicine is the emptiness of everything. The greatest action is not conforming with the worlds ways.
 * 	The greatest magic is transmuting the passions. The greatest generosity is non-attachment.
 * 	The greatest goodness is a peaceful mind. The greatest patience is humility.
 * 	The greatest effort is not concerned with results. The greatest meditation is a mind that lets go.
 * 	The greatest wisdom is seeing through appearances. 
 * </dhamma-message>
 *
 * @author Ashin Wimalajeewa
 */
package self.amigo.elem.uml;

import java.awt.*;
import java.awt.event.*;
import java.io.*;
import java.util.*;

import org.w3c.dom.*;

import self.awt.*;
import self.awt.painter.*;
import self.gee.*;
import self.lang.*;
import self.xml.*;

import self.amigo.elem.*;

public class CollaborationMessageView extends ARectangularLinkable {
	
	/**
	 * If the internal state of this class ever changes in such a way that it can't be defaulted,
	 * then the {@link #serialVersionUID} should be incremented to ensure serialized instances cleanly fail.  
	 */
	private static final long serialVersionUID = 1;
	
  final static public Font MESSAGE_FONT = new Font( "Arial", 0, 10 );
  final static public String ASYNC_PROP = "async";
  final static public String DEGREE_PROP = "degree";
  final static public String MESSAGE_PROP = "messages";

  public CollaborationMessageView() {
    delegate =  new Essential();
    setDelegate( delegate );
  }

  public class Essential extends ARectangularHandledElement {
  	
	/**
	 * If the internal state of this class ever changes in such a way that it can't be defaulted,
	 * then the {@link #serialVersionUID} should be incremented to ensure serialized instances cleanly fail.  
	 */
	private static final long serialVersionUID = 1;
	
    private Point         midPoint = new Point();
    private Point         directionHead = new Point();
    private Point         directionTail = new Point();
    private boolean       isAsync = false;
    private int           degree = 0;
    private String        message = "message()";
    private Rectangle     textFrame = new Rectangle();
    protected TextPainter textPainter;
    protected LinePainter linePainter;

    transient private TextPaintContext  ctxText = new TextPaintContext();
    private LinePaintContext  ctxLine = new LinePaintContext();

    public Essential() {
      fig.setBounds( 10, 10, 110, 80 );
      resetFrame();
    }

    public void       setLayer( IDiagramLayer layerToDrawOn, boolean add ) {
      super.setLayer( layerToDrawOn, add );
      textPainter = (TextPainter) PainterManager.getPainterForOwner( layer, TextPainter.class );
      linePainter = (LinePainter) PainterManager.getPainterForOwner( layer, LinePainter.class );
    }

    public void paint( Graphics surface ) {
      linePainter.paint( surface, ctxLine, outlineOnly );
      textPainter.paint( surface, ctxText, outlineOnly );
    }

    public void       resize( int x, int y, Point[] handle, MouseEvent e, int dragState ) {
      if ( dragState == IGraphicElement.DS_AFTER_LAST ) {
        super.resize( x, y, handle, e, dragState );
        return;
      }
      if ( (handle != null) && (handle[0] == directionHead) ) {
        pivotMessageArrow( x, y );
        return;
      }

      layer.beginUpdate();
      super.resize( x, y, handle, e, dragState );
      if ( fig.width < 110 )
        fig.width = 110;
      if ( fig.height < 80 )
        fig.height = 80;
      resetFrame();
      layer.endUpdate();
    }

    private void pivotMessageArrow( int x, int y ) {
      double num = y-midPoint.y;
      double den = x-midPoint.x;
      double tanRad = num/den;
      double invTan = Math.toDegrees( Math.atan(tanRad) );

      degree = (int) invTan;
      if ( den < 0 )
        degree += 180;
      layer.beginUpdate();
      resetFrame();
      layer.endUpdate();
    }

    // IEditableElement support
    public void       getProperties( Map store ) {
      store.put( MESSAGE_PROP, message );
      store.put( ASYNC_PROP, isAsync ? Boolean.TRUE: Boolean.FALSE );
    }

    public void       setProperties( Map data ) {
      message = (String) data.get( MESSAGE_PROP );
      isAsync = ((Boolean) data.get(ASYNC_PROP)).booleanValue();
      layer.setDirty();
    }

    // IPersistentElement support
    public void readFrom( Node self, HashMap idObjLookUp ) throws DOMException {
      super.readFrom( self, idObjLookUp );

      String degreeAsStr = DomUtils.getElementAttribute( self, DEGREE_PROP );
      degree = Integer.parseInt( degreeAsStr );
      String asyncAsString = DomUtils.getElementAttribute( self, ASYNC_PROP );
      isAsync = BooleanUtils.toValue( asyncAsString );
      Node det = DomUtils.getChildElementNode( self, MESSAGE_PROP );
      message = DomUtils.getElementText( det );
      resetFrame();
    }

    public void writeTo( Document doc, Element self, HashMap objIdLookup ) throws DOMException {
      super.writeTo( doc, self, objIdLookup );

      DomUtils.setElementAttribute( self, ASYNC_PROP, "" + isAsync );
      DomUtils.setElementAttribute( self, DEGREE_PROP, "" + degree );
      Element det = doc.createElement( MESSAGE_PROP );
      self.appendChild( det );
      DomUtils.setElementText( det, StringUtils.toEmptyIfNull(message) );
    }

    public void       getHandlePoints( java.util.List store ) {
      super.getHandlePoints( store );
      store.add( directionHead );
    }

    public void resetFrame() {
      textFrame.setBounds( fig.x, fig.y+45, fig.width, fig.height-45 );
      midPoint.setLocation( fig.x + (fig.width)/2, fig.y + (45/2) );
      int otherSide = degree + ( (degree > 180) ? -180: 180 );
      transformPoint( directionHead, degree );
      transformPoint( directionTail, otherSide );
    }

    private void transformPoint( Point toMorph, int deg ) {
      double rad = Math.toRadians( deg );
      int y = (int) ( Math.sin(rad) * 20 );
      int x = (int) ( Math.cos(rad) * 20 );
      toMorph.setLocation( midPoint.x + x, midPoint.y + y );
    }

    protected class TextPaintContext extends ATextRenderInfoAdapter {
      public TextPaintContext() {
        format = ITextRenderInfo.TRIM_FORMAT;
      }

      public String     getText() {
        return message;
      }

      public Rectangle  getBounds() {
        return textFrame;
      }

      public Font       getFont() {
        return  MESSAGE_FONT;
      }

      public Color      getColor() {
        return frameColor;
      }
    }

    protected class LinePaintContext implements ILineRenderInfo, Serializable {
    	
    	/**
    	 * If the internal state of this class ever changes in such a way that it can't be defaulted,
    	 * then the {@link #serialVersionUID} should be incremented to ensure serialized instances cleanly fail.  
    	 */
    	private static final long serialVersionUID = 1;
    	
      private ArrayList points = new ArrayList();
      public Color getColor() {
        return frameColor;
      }

      public LinePaintContext() {
        points.add( directionHead );
        points.add( directionTail );
      }

      public boolean isDashed() {
        return false;
      }

      public float getWidth() {
        return 1.0f;
      }

      public java.util.List getPoints() {
        return points;
      }

      public String getLineName() {
        return null;
      }

      public String getLineHeader() {
        return null;
      }

      public int getSideAHead() {
        if ( isAsync )
          return ILineRenderInfo.HALF_OPEN_ARROW_HEAD;
        return ILineRenderInfo.OPEN_ARROW_HEAD;
      }

      public String getSideAMajor() {
        return null;
      }

      public String getSideAMinor() {
        return null;
      }

      public int getSideBHead() {
        return ILineRenderInfo.NO_HEAD;
      }

      public String getSideBMajor() {
        return null;
      }

      public String getSideBMinor() {
        return null;
      }

      public int getHeadDiameter() {
        return 12;
      }
    }
  }
}
